import json
import datetime
from enum import Enum
from typing import Callable, Any

import httpx
from django.db.models import Q
from django.utils import timezone

from Task.models import TaskStatus, Task
from celery_server.celery import app
from celery_server.reference import TIME_DELTA

DEFAULT_TASK_FIELD = dict(expires=3600, retry=True)
COUNT = 1
N = '\n'
T = '\t'


class TaskDoingStatus(Enum):
    EMPTY = 0
    SUCCESS = 1
    ERROR = 2


def task_done(task):
    task.status = TaskStatus.DONE
    task.save()


def task_request(body):
    request_body = json.loads(body)
    if not request_body:
        print("未设置错误回调接口")
        return

    data = request_body.get('body')
    header = request_body.get('header')

    if 'method' not in request_body:
        return

    if request_body['method'] == 'post':
        print(f"POST {request_body['url']}")
        r = httpx.post(request_body['url'], json=data, headers=header)
    else:
        print(f"GET {request_body['url']}")
        r = httpx.get(request_body['url'], params=data, headers=header)

    return r


@app.task
def doing(task_pk):
    print(f"开始执行任务: {task_pk}")
    if not (task := Task.objects.filter(pk=task_pk).first()):
        print("未找到对应任务")
        return TaskDoingStatus.EMPTY
    if task.status != TaskStatus.PADDING:
        print(f'任务{task.pk}已失效')
        return TaskDoingStatus.EMPTY

    try:
        r = task_request(task.running)
        assert r.status_code < 300, f'任务{task.pk}执行失败: {r.text}'

        if task.loop:
            # 设置下一次执行的时间
            task.doing_time += timezone.timedelta(seconds=task.deadline)
            task.save()
        else:
            task_done(task)

        print(f"任务{task.pk}执行完毕")
        return TaskDoingStatus.SUCCESS

    except Exception as e:
        print(f"任务{task.pk}执行失败， 错误信息: {e}")
        task_done(task)
        print(f"执行错误回调: {task_request(task.failed)}")
        return TaskDoingStatus.ERROR


dt_fmt: Callable[[Any], Any] = lambda x: x.strftime('%Y-%m-%d %H:%M:%S')


@app.task(name='loop_query_task')
def loop_query_task():
    global COUNT

    now = timezone.now()
    print(f"{now.strftime('%Y-%m-%d %H:%M:%S')}: 开始执行 第{COUNT}次 轮询任务")

    # 查询当前时间以前的所有任务(防止遗漏任务)
    q = Q(status=TaskStatus.PADDING, doing_time__lt=now + timezone.timedelta(seconds=TIME_DELTA))
    tasks = [(task.id, task.title, task.doing_time) for task in Task.objects.filter(q)]

    print(f"第{COUNT}次轮询将要执行的任务: {N}{N.join(f'taskId:{pk}{T}{dt_fmt(dt)}{T}{title}' for pk, title, dt in tasks)}")
    COUNT += 1

    for pk, _, doing_time in tasks:
        # 遗漏的任务 执行时间在当前时间之前 设置为3秒后执行
        later = 3 if doing_time < now else (doing_time - now).seconds

        doing.apply_async(
            (pk,),
            countdown=later,
            **DEFAULT_TASK_FIELD
        )


@app.task(name='test_loop')
def test_loop():
    now = datetime.datetime.now()
    doing_time = Task.objects.first().doing_time.replace(tzinfo=None)
    print(f"{now=}, {doing_time=}")
    print(f"now-doing_time={(now - doing_time).seconds}, doing_time-now={(doing_time - now).seconds}")
